package cn.powerchaintech.common.task;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.ScheduledFuture;

public abstract class TaskExecutor implements Runnable {
    private String taskName;
    private long second;
    private String cronExpression;
    private int continuousFailureTimes;
    private int continuousSuccessTimes;
    private long elapsed;
    private LocalDateTime lastSuccessExecuteDateTime;
    private TaskLauncher taskLauncher;
    private ScheduledFuture<?> future;

    public enum TaskType {
        DELAYED, INTERVAL, ONCE, CRON
    }

    public TaskExecutor(String taskName, long second) {
        this.taskName = taskName;
        this.second = second;
    }

    public TaskExecutor(String taskName, String cronExpression) {
        this.taskName = taskName;
        this.cronExpression = cronExpression;
    }

    @Override
    public void run() {
        try {
            long start = System.currentTimeMillis();
            execute(taskName, taskLauncher);
            elapsed = System.currentTimeMillis() - start;
            continuousFailureTimes = 0;
            continuousSuccessTimes++;
            notifySuccess();
            lastSuccessExecuteDateTime = LocalDateTime.now();
        } catch (Exception ex) {
            continuousFailureTimes++;
            continuousSuccessTimes = 0;
            notifyFailure(taskName, continuousFailureTimes, taskLauncher, ex);
        }
    }

    public abstract void execute(String taskName, TaskLauncher launcher) throws Exception;

    public abstract void notifyFailure(String taskName, int consecutiveFailures, TaskLauncher launcher, Exception ex);

    public abstract void notifySuccess();

    abstract TaskType taskType();

    public abstract List<LocalDateTime> computeFireTimesBetween(LocalDateTime from, LocalDateTime to);

    public boolean cancel(boolean mayInterruptIfRunning) {
        if (future != null) {
            return future.cancel(mayInterruptIfRunning);
        }
        return false;
    }

    public long getSecond() {
        return second;
    }

    public String getCronExpression() {
        return cronExpression;
    }

    public String getTaskName() {
        return taskName;
    }

    public void setFuture(ScheduledFuture<?> future) {
        this.future = future;
    }

    protected void setTaskLauncher(TaskLauncher taskLauncher) {
        this.taskLauncher = taskLauncher;
    }

    protected TaskLauncher getTaskLauncher() {
        return this.taskLauncher;
    }

    public LocalDateTime getLastSuccessExecuteDateTime() {
        return lastSuccessExecuteDateTime;
    }

    public long getElapsed() {
        return elapsed;
    }
}
